﻿using System;
using System.Collections;
using System.Collections.Generic;

/// <summary>
/// 行为系统：用于执行带有前置、执行中、后置行为的 GameAction（游戏行为）。
/// 单例模式，确保整个游戏中只有一个实例。
/// </summary>
public class ActionSystem : Singleton<ActionSystem>
{
    // 当前正在执行的反应列表（用于嵌套递归流程）
    private List<GameAction> reactions = new();

    // 是否正在执行某个行为
    public bool IsPerforming { get; private set; } = false;

    // 不同类型 GameAction 的前置订阅者
    private static Dictionary<Type, List<Action<GameAction>>> preSubs = new();

    // 不同类型 GameAction 的后置订阅者
    private static Dictionary<Type, List<Action<GameAction>>> postSubs = new();

    // 不同类型 GameAction 的执行器
    private static Dictionary<Type, Func<GameAction, IEnumerator>> performers = new();

    /// <summary>
    /// 执行一个 GameAction，如果当前已经在执行中，则忽略
    /// </summary>
    public void Perform(GameAction action, Action OnPerformFinished = null)
    {
        if (IsPerforming) return;
        IsPerforming = true;

        // 启动协程进行流程控制
        StartCoroutine(Flow(action, () =>
        {
            IsPerforming = false;
            OnPerformFinished?.Invoke(); // 执行完毕回调
        }));
    }

    /// <summary>
    /// 添加一个反应行为（用于递归中）
    /// </summary>
    public void AddReaction(GameAction gameAction)
    {
        reactions?.Add(gameAction);
    }

    /// <summary>
    /// 行为执行的完整流程（前置 -> 执行体 -> 后置）
    /// </summary>
    private IEnumerator Flow(GameAction action, Action OnFlowFinished = null)
    {
        // 前置反应阶段
        reactions = action.PreReactions;
        PerformSubscribers(action, preSubs);
        yield return PerformReactions();

        // 执行阶段
        reactions = action.PreformReactions;
        yield return PerformPerformer(action);
        yield return PerformReactions();

        // 后置反应阶段
        reactions = action.PostReactions;
        PerformSubscribers(action, postSubs);
        yield return PerformReactions();

        // 完成流程的回调
        OnFlowFinished?.Invoke();
    }

    /// <summary>
    /// 执行行为主体 Performer
    /// </summary>
    private IEnumerator PerformPerformer(GameAction action)
    {
        Type type = action.GetType();
        if (performers.ContainsKey(type))
        {
            yield return performers[type](action);
        }                                                                                               
    }

    /// <summary>
    /// 执行订阅的 reaction 函数
    /// </summary>
    private void PerformSubscribers(GameAction action, Dictionary<Type, List<Action<GameAction>>> subs)
    {
        Type type = action.GetType();
        if (subs.ContainsKey(type))
        {
            foreach (Action<GameAction> sub in subs[type])
            {
                sub?.Invoke(action);
            }
        }
    }

    /// <summary>
    /// 执行 reaction 列表中的所有 GameAction（可递归）
    /// </summary>
    private IEnumerator PerformReactions()
    {
        foreach (var reaction in reactions)
        {
            yield return Flow(reaction);
        }
    }

    /// <summary>
    /// 注册某类 GameAction 的执行方法（行为主体逻辑）
    /// </summary>
    public static void AttachPerformer<T>(Func<T, IEnumerator> performer) where T : GameAction
    {
        Type type = typeof(T);
        // 包装类型转换器
        IEnumerator wrappedPerformer(GameAction action) => performer((T)action);

        if (performers.ContainsKey(type))
        {
            performers[type] = wrappedPerformer;
        }
        else
        {
            performers.Add(type, wrappedPerformer);
        }
    }

    /// <summary>
    /// 取消某类 GameAction 的执行方法
    /// </summary>
    public static void DetachPerformer<T>() where T : GameAction
    {
        Type type = typeof(T);
        if (performers.ContainsKey(type))
        {
            performers.Remove(type);
        }
    }

    /// <summary>
    /// 订阅某类 GameAction 的 reaction 回调（前置或后置）
    /// </summary>
    public static void SubScribeReaction<T>(Action<T> reaction, ReactionTiming timing) where T : GameAction
    {
        // 判断使用前置或后置订阅字典
        Dictionary<Type, List<Action<GameAction>>> subs = timing == ReactionTiming.PRE ? preSubs : postSubs;

        // 包装成泛型 Action<GameAction>
        void wrappedReaction(GameAction action) => reaction((T)action);

        if (subs.ContainsKey(typeof(T)))
        {
            subs[typeof(T)].Add(wrappedReaction);
        }
        else
        {
            subs.Add(typeof(T), new());
            subs[typeof(T)].Add(wrappedReaction);
        }
    }

    /// <summary>
    /// 取消某类 GameAction 的 reaction 回调（前置或后置）
    /// 注意：这里使用的 wrappedReaction 是临时创建的，与原始引用不同，无法真正移除
    /// </summary>
    public static void UnsubScribeReaction<T>(Action<T> reaction, ReactionTiming timing) where T : GameAction
    {
        Dictionary<Type, List<Action<GameAction>>> subs = timing == ReactionTiming.PRE ? preSubs : postSubs;
        if (subs.ContainsKey(typeof(T)))
        {
            // 这个 wrappedReaction 是新创建的，Remove 无法找到原来的委托对象，实际可能不会移除成功
            void wrappedReaction(GameAction action) => reaction((T)action);
            subs[typeof(T)].Remove(wrappedReaction);
        }
    }
}
